// Object.defineProperty es5

/** 1. 属性访问器 getter 和 setter*/
// 功能就是基于Object.defineProperty的
// 可以认为是defineProperty的简写
/*let obj = {
    _val: '',
    get name() {
        return this._val
    },
    set name(newVal) {
        this._val = newVal
    }
};
obj.name = 'hello';
console.log(obj.name); //hello*/


/** 2. defineProperty*/
/** 默认定义的属性不可枚举*/
/** 默认定义的属性不可重新设置值 （另外如果你设置getter/setter,那么writable选项设置会无效）*/
/** 默认定义的属性不可配置（除非你设置了setter）*/

/*let obj = {};
Object.defineProperty(obj, 'name', {
  value: 100,
  // enumerable:false, //是否可枚举 是否能被for in 所迭代 默认为false
  // writable:true //默认为false
  //configurable: true
});
//↑就等价于obj.name=100
console.log(Object.getOwnPropertyDescriptor(obj, 'name')); //{ value: 100, writable: false, enumerable: false, configurable: false } //如果是 let obj = {name:100} 这样正常赋值的话, Descriptor里的配置项默认都为true
console.log(Object.keys(obj)); //[] //默认是不可枚举的
obj.name = 200
console.log(obj.name); //100 //因为默认是不可重新修改值的 故还是100
delete obj.name
console.log(obj.name); //100 //因为默认是不可配置的 故这里 delete obj.name 无效*/

/** getter/setter*/
//使用defineProperty的getter/setter的话
//需要一个中间变量 (否则会死循环 爆栈)
/*let obj = {};
let other = '';
Object.defineProperty(obj, 'name', {
  // enumerable:false,
  // writable:true, // 是否可写 和 value连用，如果设置了get和set就无效了
  // configurable:true, //默认有了set以后，就会置为true
  get() {
    return other;
  }
  , set(value) {
    other = value;
  }

});
obj.name = '100';
console.log(obj); //{} ← 默认是不可枚举，读取不到；如果可枚举即为→ { name: [Getter/Setter] }*/


/** 3. Object.freeze(obj)*/
/*let obj = {};
let other = '';
Object.defineProperty(obj, 'name', {
  // enumerable:false,
  // writable:true, // 是否可写 和 value连用，如果设置了get和set就无效了
  // configurable:true, //默认有了set以后，就会置为true
  get() {
    return other;
  }
  , set(value) {
    other = value;
  }

});
obj.name = '100';
console.log(obj); //{} ← 默认是不可枚举，读取不到；如果可枚举即为→ { name: [Getter/Setter] }
Object.freeze(obj);
obj.age = 234;
console.log(obj.age); //undefined
//Object.defineProperty(obj,'age',{value:123}); //报错: TypeError: Cannot define property age, object is not extensible*/


/** 4. Object.getOwnPropertyDescriptor*/
//Object.getOwnPropertyDescriptor方法返回指定对象上一个自有属性对应的属性描述符。（自有属性指的是直接赋予该对象的属性，不需要从原型链上进行查找的属性）
let o = {name:'ahhh'};
let obj = {};
obj.__proto__ = o;
// console.log(obj.name); //ahhh
let val = 'ahhh';


// let descriptor = Object.getOwnPropertyDescriptor(obj,'name'); //undefined

let descriptor = Object.getOwnPropertyDescriptor(o,'name');
console.log('descriptor:',descriptor); //descriptor: { value: 'ahhh', writable: true, enumerable: true, configurable: true }
console.log('descriptor.configurable:',descriptor.configurable); //true


if(descriptor.configurable !== false){
    Object.defineProperty(o,'name',{
        configurable:true, // 是否可配置 这个属性是否能被删除
        enumerable:false, // 可枚举 es6类 原型方法 ，不可枚举 表示不能被for in 所迭代
        get(){
            return val;
        },
        set(newVal){
            val = newVal
        }
    })
}
o.name = 'hello'
// delete o.name;
console.log(o.name); //hello
